"""
重试辅助工具
为 API 调用提供重试机制，处理网络错误
"""
import time
import functools
from typing import Callable, Any, Optional, Tuple, Type


def retry_on_error(
    max_retries: int = 3,
    delay: float = 1.0,
    backoff: float = 2.0,
    exceptions: Tuple[Type[Exception], ...] = (Exception,),
    on_retry: Optional[Callable] = None
):
    """
    重试装饰器，在发生错误时自动重试

    Args:
        max_retries: 最大重试次数
        delay: 初始延迟时间（秒）
        backoff: 延迟时间的倍增因子
        exceptions: 需要重试的异常类型
        on_retry: 重试时的回调函数

    Example:
        @retry_on_error(max_retries=3, delay=1.0)
        def my_api_call():
            # API 调用
            pass
    """
    def decorator(func: Callable) -> Callable:
        @functools.wraps(func)
        def wrapper(*args, **kwargs) -> Any:
            current_delay = delay
            last_exception = None

            for attempt in range(max_retries + 1):
                try:
                    return func(*args, **kwargs)
                except exceptions as e:
                    last_exception = e

                    if attempt < max_retries:
                        # 还有重试机会
                        if on_retry:
                            on_retry(attempt + 1, max_retries, e)
                        else:
                            print(f"[Retry {attempt + 1}/{max_retries}] {func.__name__} failed: {str(e)}")

                        time.sleep(current_delay)
                        current_delay *= backoff
                    else:
                        # 已达到最大重试次数
                        print(f"[Failed] {func.__name__} failed after {max_retries} retries")
                        raise last_exception

            # 理论上不会到这里，但为了类型检查
            raise last_exception

        return wrapper
    return decorator


def safe_api_call(
    func: Callable,
    *args,
    default_value: Any = None,
    error_message: str = "API call failed",
    **kwargs
) -> Any:
    """
    安全的 API 调用，捕获异常并返回默认值

    Args:
        func: 要调用的函数
        *args: 位置参数
        default_value: 发生错误时的默认返回值
        error_message: 错误消息前缀
        **kwargs: 关键字参数

    Returns:
        函数返回值或默认值
    """
    try:
        return func(*args, **kwargs)
    except Exception as e:
        print(f"[Error] {error_message}: {str(e)}")
        return default_value


def _test_retry():
    """测试重试装饰器"""
    attempt_count = [0]  # 使用列表来避免 nonlocal 问题

    @retry_on_error(max_retries=3, delay=0.5, backoff=2.0)
    def test_function():
        """测试函数，前2次失败，第3次成功"""
        attempt_count[0] += 1

        if attempt_count[0] < 3:
            raise ConnectionError(f"Connection failed (attempt {attempt_count[0]})")

        return "Success!"

    print("测试 1: 重试装饰器")
    try:
        result = test_function()
        print(f"结果: {result}")
        print(f"总尝试次数: {attempt_count[0]}")
    except Exception as e:
        print(f"失败: {str(e)}")


if __name__ == "__main__":
    print("=" * 80)
    print("重试辅助工具测试")
    print("=" * 80)
    print()

    _test_retry()

    print()
    print("=" * 80)
    print("✅ 测试完成")
    print("=" * 80)
